package com.linked.gateway.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.linked.gateway.config.GatewaySwitchConfig;
import com.linked.gateway.config.IPAccessControlConfig;
import com.linked.gateway.feign.IBaseManageFeign;
import com.linked.gateway.feign.IUserManageFeign;
import com.linked.universal.common.LinkedResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;


import java.util.List;

/**
 * @author :dbq
 * @date : 2022/9/20 9:41
 */
@Component
public class IPAccessControlFilter implements GlobalFilter, Ordered {

    private final static Logger LOGGER = LoggerFactory.getLogger(IPAccessControlFilter.class);

    private final GatewaySwitchConfig switchConfig;

    private final IPAccessControlConfig ipConfig;

    private final ObjectMapper mapper;

    private final IBaseManageFeign baseManageFeign;

    private final IUserManageFeign userManageFeign;

    @Autowired
    public IPAccessControlFilter(IPAccessControlConfig ipConfig, ObjectMapper mapper, GatewaySwitchConfig switchConfig, IBaseManageFeign baseManageFeign, IUserManageFeign userManageFeign) {
        this.mapper = mapper;
        this.ipConfig = ipConfig;
        this.switchConfig = switchConfig;
        this.baseManageFeign = baseManageFeign;
        this.userManageFeign = userManageFeign;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("ip过滤器 访问路径：" + request.getURI().toString());
        }

        String accessIP = request.getURI().getAuthority();
        /**
         * 一、黑名单处理
         * */
        if (switchConfig.isBlackSwitch() && !ipAccessHandle(accessIP, 2)) {
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            return exchange.getResponse().setComplete();
        }
        /**
         * 二、白名单处理
         * */
        if (switchConfig.isWhiteSwitch() && !ipAccessHandle(accessIP, 1)) {
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }


        ServerHttpResponse response = exchange.getResponse();
        return chain.filter(exchange);
    }


    /**
     * 返回true,允许访问
     * 返回false,不允许访问
     */
    private boolean ipAccessHandle(String accessIP, Integer controlType) {

        List<String> accessList = null;
        try {
            LinkedResult result = baseManageFeign.queryPassList(controlType);
            if (result.isSuccess()) {
                accessList = (List<String>) result.getData();
            } else {
                LOGGER.info("查询不到ip地址！");
                //没有正确结果不让访问
                return false;
            }
            switch (controlType) {
                //黑名单，如果列表中包涵数据，则返回false,不许继续访问
                case 2:

                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("黑名单" + " ip列表：" + accessList);
                    }
                    return !accessList.contains(accessIP);
                //白名单，如果列表中包涵数据，则返回true,允许访问
                case 1:
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("白名单" + " ip列表：" + accessList);
                    }
                    return accessList.contains(accessIP);
                default:
                    return true;
            }
        } catch (Exception e) {
            LOGGER.error("处理" + accessIP + "出现问题！   访问类型：" + controlType, e);
        }
        return false;
    }


    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE + 1;
    }
}
